package gnss

import (
	"dgo/goutils/gis"
	"dgo/goutils/utils"
	"fmt"
	"strings"
	"time"
)

/*
*

	  connstring ntripclt://qlz:qulizhong123@58.49.94.212:2101/RTCM3EPH-MGEX-BDS/GAA
	  donefunc
	  	errcode: 1000 尚未连接, 时间太短?
				 1001 连接错误
				 1002 认证失败
				 1003 传输数据异常
	             1005 缺少1005数据
	             1006 与基站距离太长(超过8KM)
	             0   正常
*/
func NtripCltTestOnce(connstring string, userAgent string, duration time.Duration, onEpochFunc func(epoch *GnssSVEpoch), donefunc func(recvsize int, errcode int, errmsg string)) {
	conf := ParseNtripClientConnectString(connstring)
	if len(conf.Addr) == 0 {
		if donefunc != nil {
			donefunc(0, -1, "配置错误,测试失败")
		}
	}

	stepFlag := 0 // 5 is done, 1:认证成功, -1:异常
	var errcode int = 1000
	var errmsg string = ""
	//

	if len(userAgent) == 0 {
		userAgent = GetUserAgentRand()
	}

	go func() {
		if utils.GoFunCatchException {
			defer utils.PanicHandler()
		}

		ntripclt := NewNtripClientCltSimple(conf.Addr)
		err := ntripclt.Open()
		if err != nil {
			errcode = 1001
			errmsg = fmt.Sprintf("连接异常:%s", err.Error())
			donefunc(0, errcode, errmsg)
			return
		}

		err = ntripclt.RequestData(conf.User, conf.Pass, conf.MountPoint, userAgent)
		if err != nil {
			errcode = 1001
			errmsg = fmt.Sprintf("发送认证数据异常:%s", err.Error())
			donefunc(0, errcode, errmsg)
			return
		}

		var recv_size int = 0

		var vrsB, vrsL, vrsH float64
		var latest1005 time.Time

		utils.GoFunc2(func() {
			buf := make([]byte, 1024)
			yobsDe := NewGnssSVEpochRtcmDecoder()
			yobsDe.OnRtcmBuf = func(msgid uint16, buf []byte) bool {
				if msgid == 1005 || msgid == 1006 {
					latest1005 = time.Now()
					rec := &GnssStation{}
					if DecodeRtcm1005(rec, buf, 24+12) > 0 {
						x, y, z := utils.Round64(rec.Pos[0], 5), utils.Round64(rec.Pos[1], 5), utils.Round64(rec.Pos[2], 5)
						vrsB, vrsL, vrsH = gis.EcefXyz2PosiLatLngH(x, y, z)
					}
				}
				return true
			}
			yobsDe.OnEpochFunc = func(epoch *GnssSVEpoch, checktype int) {
				if onEpochFunc != nil {
					onEpochFunc(epoch)
				}
			}
			for errcode == 1000 {
				n, err := ntripclt.ReadEx(buf)
				if errcode != 1000 {
					break
				}
				if err != nil {
					if stepFlag == 0 {
						errcode = 1001
						errmsg = fmt.Sprintf("发送认证数据异常:%s", err.Error())
					}
					stepFlag = -1
				} else {
					if stepFlag == 0 {
						str := string(buf[:n])
						if strings.Contains(str, "200 OK") {
							stepFlag = 1
						} else {
							errcode = 1002
							errmsg = fmt.Sprintf("认证失败:%s", str)
							stepFlag = -1
						}
					} else {
						recv_size += n
						yobsDe.InputBuf(buf[:n])
					}
				}
			}
		})

		time.Sleep(time.Millisecond * 100)
		t1 := time.Now()
		var nmea *gis.NMEA = nil
		var lastNmeaT time.Time

		for errcode == 1000 {
			if time.Since(t1) > duration {
				stepFlag = 5
				ntripclt.Close()
				if stepFlag == 0 {
					errcode = 1002
					errmsg = "认证未响应"
				} else {
					if errcode == 1000 {
						if recv_size == 0 {
							errcode = 1003
							if len(errmsg) == 0 {
								errmsg = "未收到任何数据"
							}
						} else {
							errcode = 0
							if len(errmsg) == 0 {
								errmsg = "测试成功"
							}
						}
					}

				}
				break
			}

			if stepFlag == 1 { // 发送数据
				if len(conf.NMEA) > 0 {
					if nmea == nil {
						nmea = gis.NewNMEA()
						nmea.ParseText(conf.NMEA)
					}
					if lastNmeaT.IsZero() || time.Since(lastNmeaT).Seconds() >= 10 {
						nmea.UpdateUTCTime()
						err = ntripclt.ReportNMEA(nmea.Encode())
						if err != nil {
							errcode = 1003
							errmsg = fmt.Sprintf("发送NMEA数据异常:%s", err.Error())
							break
						}
					}
				}
			}
			time.Sleep(time.Millisecond * 200)
		}

		if errcode == 0 {
			if nmea != nil && nmea.GetLng() != 0 {
				if latest1005.IsZero() {
					errcode = 1005
					errmsg = "未收到1005/1006位置数据"
				} else if vrsB == 0 || vrsH == 0 || vrsL == 0 {
					errcode = 1005
					errmsg = "未收到1005/1006位置数据"
				} else {
					b, l, _ := nmea.GetPosiBLH()
					dis := gis.CalcuDis(l, b, vrsL, vrsB)
					if dis > 8000 {
						errcode = 1006
						errmsg = fmt.Sprintf("虚拟基站距离(%.2fKM)过长", dis)
					}
				}
			}
		}

		donefunc(recv_size, errcode, errmsg)
	}()
}

func NtripCltPull1005Raw(connstring string, userAgent string, timeout time.Duration, cnt int, onBuf func(buf []byte)) (staid uint16, x, y, z float64, err error) {
	conf := ParseNtripClientConnectString(connstring)
	if len(conf.Addr) == 0 {
		err = fmt.Errorf("配置错误,测试失败")
		return
	}

	if len(userAgent) == 0 {
		userAgent = GetUserAgentRand()
	}

	ntripclt := NewNtripClientCltSimple(conf.Addr)
	err = ntripclt.Open()
	if err != nil {
		return
	}

	err = ntripclt.RequestData(conf.User, conf.Pass, conf.MountPoint, userAgent)
	if err != nil {
		return
	}
	fmt.Println(ntripclt.RequestHead)

	buf, e1 := ntripclt.ReadFirst()
	if e1 != nil {
		ntripclt.RequestDis(fmt.Sprintf("认证失败:%s", e1.Error()))
		err = e1
		return
	}

	var Terminated int = 0

	cnt_1005 := 0
	rtcmRaw := NewRtcm32RawBufDecoder("")
	rtcmRaw.OnRtcmBuf = func(rtcmBuf []byte) {
		msgid := GetRtcmMsgId(rtcmBuf, 24)
		if msgid == 1005 || msgid == 1006 {
			rec := &GnssStation{}
			if DecodeRtcm1005V1(rec, rtcmBuf, 24) > 24 {
				x, y, z = rec.Pos[0], rec.Pos[1], rec.Pos[2]
				staid = rec.StationId
				cnt_1005++
				if cnt_1005 >= cnt {
					Terminated = 1
				}

			}
		}
	}

	nmeaPs := gis.NewNMEA()
	nmeaPs.ParseText(conf.NMEA)
	var sendNmeaFunc = func() error {
		nmeaPs.UpdateUTCTime()
		nmea := nmeaPs.Encode()
		fmt.Println(utils.NowString(), nmea)
		_, e1 := ntripclt.Write([]byte(nmea + "\r\n"))
		if e1 != nil {
			ntripclt.RequestDis(fmt.Sprintf("发送NMEA数据时出现异常:%s", err.Error()))
			return e1
		}
		return nil
	}

	// 发送GGA
	go func() {
		startT := time.Now()
		sendNmeaFunc()
		lastSent_t := time.Now()
		for Terminated == 0 {
			time.Sleep(time.Millisecond * 200)
			if timeout > 0 && time.Since(startT) > timeout {
				Terminated = 1
				err = fmt.Errorf("执行超时")
				ntripclt.RequestDis("超时断线")
				continue
			}
			if Terminated == 0 && time.Since(lastSent_t).Seconds() >= 10 {
				sendNmeaFunc()
				lastSent_t = time.Now()
			}
		}
	}()

	buf = make([]byte, 1024)
	for Terminated == 0 {
		n, e1 := ntripclt.ReadEx(buf)
		if e1 != nil {
			if err == nil {
				err = e1
			}
			ntripclt.RequestDis(fmt.Sprintf("读取数据异常:%s", err.Error()))
			return
		}
		onBuf(buf[:n])
		rtcmRaw.InputBuf(buf[:n])
	}

	return
}

func NtripCltPull1005(connstring string, userAgent string, timeout time.Duration, cnt int) (staid uint16, x, y, z float64, err error) {
	conf := ParseNtripClientConnectString(connstring)
	if len(conf.Addr) == 0 {
		err = fmt.Errorf("配置错误,测试失败")
		return
	}

	if len(userAgent) == 0 {
		userAgent = GetUserAgentRand()
	}

	ntripclt := NewNtripClientCltSimple(conf.Addr)
	err = ntripclt.Open()
	if err != nil {
		return
	}

	err = ntripclt.RequestData(conf.User, conf.Pass, conf.MountPoint, userAgent)
	if err != nil {
		return
	}
	//fmt.Println(ntripclt.RequestHead)

	buf, e1 := ntripclt.ReadFirst()
	if e1 != nil {
		ntripclt.RequestDis(fmt.Sprintf("认证失败:%s", e1.Error()))
		err = e1
		return
	}

	var Terminated int = 0

	cnt_1005 := 0
	rtcmRaw := NewRtcm32RawBufDecoder("")
	rtcmRaw.OnRtcmBuf = func(rtcmBuf []byte) {
		msgid := GetRtcmMsgId(rtcmBuf, 24)
		if msgid == 1005 || msgid == 1006 {
			rec := &GnssStation{}
			if DecodeRtcm1005V1(rec, rtcmBuf, 24) > 24 {
				x, y, z = rec.Pos[0], rec.Pos[1], rec.Pos[2]
				staid = rec.StationId
				cnt_1005++
				if cnt_1005 >= cnt {
					Terminated = 1
				}

			}
		}
	}

	nmeaPs := gis.NewNMEA()
	nmeaPs.ParseText(conf.NMEA)
	var sendNmeaFunc = func() error {
		nmeaPs.UpdateUTCTime()
		nmea := nmeaPs.Encode()
		//fmt.Println(utils.NowString(), nmea)
		_, e1 := ntripclt.Write([]byte(nmea + "\r\n"))
		if e1 != nil {
			ntripclt.RequestDis(fmt.Sprintf("发送NMEA数据时出现异常:%s", err.Error()))
			return e1
		}
		return nil
	}

	// 发送GGA
	go func() {
		startT := time.Now()
		sendNmeaFunc()
		lastSent_t := time.Now()
		for Terminated == 0 {
			time.Sleep(time.Millisecond * 200)
			if timeout > 0 && time.Since(startT) > timeout {
				Terminated = 1
				err = fmt.Errorf("执行超时")
				ntripclt.RequestDis("超时断线")
				continue
			}
			if Terminated == 0 && time.Since(lastSent_t).Seconds() >= 10 {
				sendNmeaFunc()
				lastSent_t = time.Now()
			}
		}
	}()

	buf = make([]byte, 1024)
	for Terminated == 0 {
		n, e1 := ntripclt.ReadEx(buf)
		if e1 != nil {
			if err == nil {
				err = e1
			}
			ntripclt.RequestDis(fmt.Sprintf("读取数据异常:%s", err.Error()))
			return
		}
		rtcmRaw.InputBuf(buf[:n])
	}

	return
}
